package com.ibm.android.camera;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.util.Log;
import android.view.SurfaceHolder;

public class HttpCamera implements ICamera {
	class HttpThread extends Thread {
		private boolean mRun = false;
		private SurfaceHolder mSurfaceHolder;

		public HttpThread(SurfaceHolder surfaceHolder) {
			mSurfaceHolder = surfaceHolder;
			mRun = false;
		}

		@Override
		public void run() {
			while (mRun) {
				Canvas c = null;
				try {
					c = mSurfaceHolder.lockCanvas(null);
					synchronized (mSurfaceHolder) {
						doDraw(c);
					}
				} finally {
					// do this in a finally so that if an exception is thrown
					// during the above, we don't leave the Surface in an
					// inconsistent state
					if (c != null) {
						mSurfaceHolder.unlockCanvasAndPost(c);
					}
				}
			}
		}

		private void doDraw(Canvas canvas) {
			Bitmap bitmap = captureImage();
			if (bitmap == null || canvas == null) {
				return;
			}

			Rect bounds = new Rect(0, 0, canvas.getWidth(), canvas.getHeight());
			Rect dest = new Rect(bounds);
			dest.bottom = bitmap.getHeight() * bounds.right / bitmap.getWidth();
			dest.offset(0, (bounds.bottom - dest.bottom) / 2);
			Paint paint = new Paint();
			canvas.drawBitmap(bitmap, null, dest, paint);

			if (mCallback != null) {
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				bitmap.compress(CompressFormat.JPEG, 100, bos);
				mCallback.onPreviewFrame(bos.toByteArray(), null);
				if (mOneShot)
					mCallback = null;
			}
		}

		public void setRunning(boolean run) {
			mRun = run;
		}
	}

	private static final int CONNECT_TIMEOUT = 1000;
	private static final int SOCKET_TIMEOUT = 1000;

	private Parameters mParameters;
	private HttpThread mThread;
	private String mUrl;
	private PreviewCallback mCallback;
	private boolean mOneShot;
	private Point mPreviewSize;

	public HttpCamera(String url, Point previewSize) {
		mUrl = url;
		Camera c = Camera.open();
		mPreviewSize = previewSize;
		mParameters = c.getParameters();
		mParameters.setPreviewFormat(PixelFormat.JPEG);
		mParameters.setPreviewSize(mPreviewSize.x, mPreviewSize.y);
		c.release();
	}

	private Bitmap captureImage() {
		Bitmap bitmap = null;
		try {
			URL url = new URL(this.mUrl);
			URLConnection conn;
			conn = url.openConnection();
			if (!(conn instanceof HttpURLConnection)) {
				return null;
			}

			HttpURLConnection httpConnection = (HttpURLConnection) conn;
			httpConnection.setAllowUserInteraction(false);
			httpConnection.setConnectTimeout(CONNECT_TIMEOUT);
			httpConnection.setReadTimeout(SOCKET_TIMEOUT);
			httpConnection.setInstanceFollowRedirects(true);
			httpConnection.setRequestMethod("GET");

			httpConnection.connect();
			int response = httpConnection.getResponseCode();
			if (response != HttpURLConnection.HTTP_OK) {
				Log.e("TEST", "Response code: " + response);
				return null;
			}

			InputStream in = httpConnection.getInputStream();
			bitmap = BitmapFactory.decodeStream(in);
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bitmap;
	}

	@Override
	public void setPreviewDisplay(SurfaceHolder holder) throws IOException {
		mThread = new HttpThread(holder);
	}

	@Override
	public Parameters getParameters() {
		return mParameters;
	}

	@Override
	public void setParameters(Parameters p) {
		mParameters = p;
		// These are not variable for the HttpCamera. It's always the same.
		mParameters.setPreviewSize(mPreviewSize.x, mPreviewSize.y);
		mParameters.setPictureFormat(PixelFormat.JPEG);
	}

	@Override
	public void startPreview() {
		mThread.setRunning(true);
		mThread.start();

	}

	@Override
	public void stopPreview() {
		mThread.setRunning(false);
	}

	@Override
	public void open() {
		// TODO Auto-generated method stub

	}

	@Override
	public void release() {
		// TODO Auto-generated method stub

	}

	@Override
	public void setPreviewCallback(PreviewCallback callback) {
		mCallback = callback;
		mOneShot = false;
	}

	@Override
	public void setOneShotPreviewCallback(PreviewCallback callback) {
		mCallback = callback;
		mOneShot = true;
	}
}
